package xyz.yuzegod.megawalls.database;

import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.plugin.Plugin;
import xyz.yuzegod.megawalls.MegaWalls;

import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;

public class DataBase
{
    private final DataBaseCore dataBaseCore;
    private Logger logger;
    
    public DataBase(final DataBaseCore core) {
        this.dataBaseCore = core;
        this.logger = MegaWalls.getInstance().getLogger();
    }
    
    public static DataBase create(final ConfigurationSection dbConfig) {
        final Type type = Type.valueOf(dbConfig.getString("type", "SQLITE").toUpperCase());
        switch (type) {
            case MYSQL: {
                return new DataBase(new MySQLCore(dbConfig));
            }
            default: {
                return new DataBase(new SQLiteCore((Plugin)MegaWalls.getInstance(), dbConfig));
            }
        }
    }
    
    public boolean close() {
        try {
            this.dataBaseCore.getConnection().close();
            return true;
        }
        catch (SQLException ex) {
            return false;
        }
    }
    
    public boolean createTables(final String tableName, final KeyValue fields, final String Conditions) {
        try {
            this.dataBaseCore.createTables(tableName, fields, Conditions);
            return this.isTableExists(tableName);
        }
        catch (Exception e) {
            this.sqlerr("创建数据表 " + tableName + " 异常(内部方法)...", e);
            return false;
        }
    }
    
    public int dbDelete(final String tableName, final KeyValue fields) {
        final String sql = "DELETE FROM `" + tableName + "` WHERE " + fields.toWhereString();
        try {
            return this.dataBaseCore.executeUpdate(sql);
        }
        catch (Exception e) {
            this.sqlerr(sql, e);
            return 0;
        }
    }
    
    public boolean dbExist(final String tableName, final KeyValue fields) {
        final String sql = "SELECT * FROM " + tableName + " WHERE " + fields.toWhereString();
        try {
            return this.dataBaseCore.executeQuery(sql).next();
        }
        catch (Exception e) {
            this.sqlerr(sql, e);
            return false;
        }
    }
    
    public int dbInsert(final String tabName, final KeyValue fields) {
        final String sql = "INSERT INTO `" + tabName + "` " + fields.toInsertString();
        try {
            return this.dataBaseCore.executeUpdate(sql);
        }
        catch (Exception e) {
            this.sqlerr(sql, e);
            return 0;
        }
    }
    
    public List<KeyValue> dbSelect(final String tableName, final KeyValue fields, final KeyValue selCondition) {
        final String sql = "SELECT " + fields.toKeys() + " FROM `" + tableName + "`" + ((selCondition == null) ? "" : (" WHERE " + selCondition.toWhereString()));
        final List<KeyValue> kvlist = new ArrayList<KeyValue>();
        try {
            final ResultSet dbresult = this.dataBaseCore.executeQuery(sql);
            while (dbresult.next()) {
                final KeyValue kv = new KeyValue();
                for (final String col : fields.getKeys()) {
                    kv.add(col, dbresult.getString(col));
                }
                kvlist.add(kv);
            }
        }
        catch (Exception e) {
            this.sqlerr(sql, e);
        }
        return kvlist;
    }
    
    public String dbSelectFirst(final String tableName, final String fields, final KeyValue selConditions) {
        final String sql = "SELECT " + fields + " FROM " + tableName + " WHERE " + selConditions.toWhereString() + " limit 1";
        try {
            final ResultSet dbresult = this.dataBaseCore.executeQuery(sql);
            if (dbresult.next()) {
                return dbresult.getString(fields);
            }
        }
        catch (Exception e) {
            this.sqlerr(sql, e);
        }
        return null;
    }
    
    public int dbUpdate(final String tabName, final KeyValue fields, final KeyValue upCondition) {
        final String sql = "UPDATE `" + tabName + "` SET " + fields.toUpdateString() + " WHERE " + upCondition.toWhereString();
        try {
            return this.dataBaseCore.executeUpdate(sql);
        }
        catch (Exception e) {
            this.sqlerr(sql, e);
            return 0;
        }
    }
    
    public DataBaseCore getDataBaseCore() {
        return this.dataBaseCore;
    }
    
    public boolean isValueExists(final String tableName, final KeyValue fields, final KeyValue selCondition) {
        final String sql = "SELECT " + fields.toKeys() + " FROM `" + tableName + "`" + ((selCondition == null) ? "" : (" WHERE " + selCondition.toWhereString()));
        try {
            final ResultSet dbresult = this.dataBaseCore.executeQuery(sql);
            return dbresult.next();
        }
        catch (Exception e) {
            this.sqlerr(sql, e);
            return false;
        }
    }
    
    public boolean isFieldExists(final String tableName, final KeyValue fields) {
        try {
            final DatabaseMetaData dbm = this.dataBaseCore.getConnection().getMetaData();
            final ResultSet tables = dbm.getTables(null, null, tableName, null);
            if (tables.next()) {
                final ResultSet f = dbm.getColumns(null, null, tableName, fields.getKeys()[0]);
                return f.next();
            }
        }
        catch (SQLException e) {
            this.sqlerr("判断 表名:" + tableName + " 字段名:" + fields.getKeys()[0] + " 是否存在时出错!", e);
        }
        return false;
    }
    
    public boolean isTableExists(final String tableName) {
        try {
            final DatabaseMetaData dbm = this.dataBaseCore.getConnection().getMetaData();
            final ResultSet tables = dbm.getTables(null, null, tableName, null);
            return tables.next();
        }
        catch (SQLException e) {
            this.sqlerr("判断 表名:" + tableName + " 是否存在时出错!", e);
            return false;
        }
    }
    
    public void sqlerr(final String sql, final Exception e) {
        this.logger.warning("数据库操作出错: " + e.getMessage());
        this.logger.warning("SQL查询语句: " + sql);
    }
    
    enum Type
    {
        MYSQL, 
        SQLITE;
    }
}
